home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Cafe 3
/
Visual Cafe 3.ISO
/
Vcafe
/
JFC.bin
/
JEditorPane.java
< prev
next >
Wrap
Text File
|
1998-06-30
|
18KB
|
555 lines
/*
* @(#)JEditorPane.java 1.46 98/04/20
*
* Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*
*/
package com.sun.java.swing;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.Hashtable;
import java.io.*;
import com.sun.java.swing.plaf.*;
import com.sun.java.swing.text.*;
import com.sun.java.swing.event.*;
import com.sun.java.swing.text.html.*;
import com.sun.java.accessibility.*;
/**
* A text pane to edit various kinds of content, such
* as html and rtf. This component uses implementations of the
* EditorKit to accomplish its behavior. It effectively
* morphs into the proper kind of text editor for the kind
* of content it is given.
* <p>
* The content type that editor is bound to at any given
* time is determined by the EditorKit currently installed.
* If the content is set to a new URL, its type is used
* to determine the EditorKit that should be used to load
* the content.
* <p>
* For the keyboard keys used by this component in the standard Look and
* Feel (L&F) renditions, see the
* <a href="doc-files/Key-Index.html#JEditorPane">JEditorPane</a> key assignments.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*
* @beaninfo
* attribute: isContainer false
*
* @author Timothy Prinzing
* @version 1.46 04/20/98
*/
public class JEditorPane extends JTextComponent {
/**
* Constructs a new JEditorPane. The document model is set to null.
*/
public JEditorPane() {
super();
}
/**
* Creates a JEditorPane based on a specified URL for input.
*
* @param initialPage the URL
* @exception IOException if the URL is null or cannot be accessed
*/
public JEditorPane(URL initialPage) throws IOException {
this();
setPage(initialPage);
}
/**
* Creates a JEditorPane based on a string containing a URL specification.
*
* @param url the URL
* @exception IOException if the URL is null or cannot be accessed
*/
public JEditorPane(String url) throws IOException {
this();
setPage(url);
}
/**
* Adds a hyperlink listener for notification of any changes, for example
* when a link is selected and entered.
*
* @param listener the listener
*/
public synchronized void addHyperlinkListener(HyperlinkListener listener) {
listenerList.add(HyperlinkListener.class, listener);
}
/**
* Removes a hyperlink listener.
*
* @param listener the listener
*/
public synchronized void removeHyperlinkListener(HyperlinkListener listener) {
listenerList.remove(HyperlinkListener.class, listener);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. This is normally called
* by the currently installed EditorKit if a content type
* that supports hyperlinks is currently active and there
* was activity with a link. The listener list is processed
* last to first.
*
* @param e the event
* @see EventListenerList
*/
public void fireHyperlinkUpdate(HyperlinkEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==HyperlinkListener.class) {
((HyperlinkListener)listeners[i+1]).hyperlinkUpdate(e);
}
}
}
/**
* Sets the current url being displayed. The content type of the
* pane is set, and if the editor kit for the pane is non-null, then
* a new default document is created and the URL is read into it.
*
* @param page the URL of the page
* @exception IOException for a null or invalid page specification
*/
public void setPage(URL page) throws IOException {
if (page == null) {
throw new IOException("invalid url");
}
InputStream in = page.openStream();
URLConnection conn = page.openConnection();
String type = conn.getContentType();
setContentType(type);
if (kit != null) {
Document doc = kit.createDefaultDocument();
doc.putProperty(Document.StreamDescriptionProperty, page);
try {
kit.read(in, doc, 0);
setDocument(doc);
} catch (BadLocationException e) {
throw new IOException(e.getMessage());
}
}
}
/**
* Gets the current url being displayed. If a URL was
* not specified in the creation of the document, this
* will return null, and relative URL's will not be
* resolved.
*
* @return the URL
*/
public URL getPage() {
return (URL) getDocument().getProperty(Document.StreamDescriptionProperty);
}
/**
* Sets the current url being displayed.
*
* @param url the URL for display
* @exception IOException for a null or invalid URL specification
*/
public void setPage(String url) throws IOException {
if (url == null) {
throw new IOException("invalid url");
}
URL page = new URL(url);
setPage(page);
}
/**
* Gets the class ID for the UI.
*
* @return the ID ("EditorPaneUI")
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return "EditorPaneUI";
}
/**
* Creates the default editor kit (PlainEditorKit) for when
* the component is first created.
*
* @return the editor kit
*/
protected EditorKit createDefaultEditorKit() {
return new PlainEditorKit();
}
/**
* Fetches the currently installed kit for handling
* content. createDefaultEditorKit() is called to set up a default
* if necessary.
*
* @return the editor kit
*/
public final EditorKit getEditorKit() {
if (kit == null) {
kit = createDefaultEditorKit();
}
return kit;
}
/**
* Gets the type of content that this editor
* handles.
*
* @return the content type, null if no editor kit set
*/
public final String getContentType() {
return (kit != null) ? kit.getContentType() : null;
}
/**
* Sets the type of content that this editor
* handles. This calls <code>getEditorKitForContentType</code>,
* and then <code>setEditorKit</code> if an editor kit can
* be successfully located. This is a convenience method
* that can be used as an alternative to calling
* <code>setEditorKit</code> directly.
*
* @param type the non-null mime type for the content editing
* support.
* @see #getContentType
* @beaninfo
* description: the type of content
*/
public final void setContentType(String type) {
if ((kit == null) || (! type.equals(kit.getContentType()))) {
EditorKit k = getEditorKitForContentType(type);
if (k != null) {
setEditorKit(k);
}
}
}
/**
* Sets the currently installed kit for handling
* content. This is the bound property that
* establishes the content type of the editor.
* Any old kit is first deinstalled, then if kit is non-null,
* the new kit is installed, and a default document created for it.
* A PropertyChange event ("editorKit") is always fired when
* setEditorKit() is called.
*
* @param kit the desired editor behavior.
* @see #getEditorKit
* @beaninfo
* description: the currently installed kit for handling content
* bound: true
* expert: true
*/
public void setEditorKit(EditorKit kit) {
EditorKit old = this.kit;
if (old != null) {
old.deinstall(this);
}
this.kit = kit;
if (this.kit != null) {
this.kit.install(this);
setDocument(this.kit.createDefaultDocument());
}
firePropertyChange("editorKit", old, kit);
}
/**
* Fetches the editor kit to use for the given type
* of content. This is called when a type is requested
* that doesn't match the currently installed type.
* If the component doesn't have an EditorKit registered
* for the given type, it will try to create an
* EditorKit from the default EditorKit registry.
* If that fails, a PlainEditorKit is used on the
* assumption that all text documents can be represented
* as plain text.
* <p>
* This method can be reimplemented to use some
* other kind of type registry. This can
* be reimplemented to use the Java Activation
* Framework for example.
*
* @param type the non-null content type
* @return the editor kit
*/
public EditorKit getEditorKitForContentType(String type) {
if (typeHandlers == null) {
typeHandlers = new Hashtable(3);
}
EditorKit k = (EditorKit) typeHandlers.get(type);
if (k == null) {
k = createEditorKitForContentType(type);
if (k != null) {
setEditorKitForContentType(type, k);
}
}
if (k == null) {
k = new DefaultEditorKit();
}
return k;
}
/**
* Directly set the editor kit to use for the given type. A
* look-and-feel implementation might use this in conjunction
* with createEditorKitForContentType to install handlers for
* content types with a look-and-feel bias.
*
* @param type the non-null content type
* @param k the editor kit to be set
*/
public void setEditorKitForContentType(String type, EditorKit k) {
if (typeHandlers == null) {
typeHandlers = new Hashtable(3);
}
typeHandlers.put(type, k);
}
/**
* Create a handler for the given type from the default registry
* of editor kits. The registry is created if necessary. An attempt
* is made to dynamically load the prototype of the given kit. If
* successful it is cloned and returned.
*
* @param type the content type
* @return the editor kit, or null if one cannot be created
*/
public static EditorKit createEditorKitForContentType(String type) {
EditorKit k = null;
Hashtable kitRegistry =
(Hashtable)SwingUtilities.appContextGet(kitRegistryKey);
if (kitRegistry == null) {
// nothing has been loaded yet.
kitRegistry = new Hashtable();
SwingUtilities.appContextPut(kitRegistryKey, kitRegistry);
} else {
k = (EditorKit) kitRegistry.get(type);
}
if (k == null) {
// try to dynamically load the support
String classname = (String) getKitTypeRegistry().get(type);
try {
Class c = Class.forName(classname);
k = (EditorKit) c.newInstance();
kitRegistry.put(type, k);
} catch (Throwable e) {
e.printStackTrace();
k = null;
}
}
// create a copy of the prototype or null if there
// is no prototype.
if (k != null) {
return (EditorKit) k.clone();
}
return null;
}
/**
* Establishes the default bindings of type to name.
* The class will be dynamically loaded later when actually
* needed, and can be safely changed before attempted uses
* to avoid loading unwanted classes.
*
* @param type the non-null content type
* @param classname the class to load later
*/
public static void registerEditorKitForContentType(String type, String classname) {
getKitTypeRegistry().put(type, classname);
}
// --- JComponent methods ---------------------------------
/**
* Turns off tab traversal once focus gained.
*
* @return true, to indicate that the focus is being managed
*/
public boolean isManagingFocus() {
return true;
}
// --- Scrollable ----------------------------------------
/**
* Returns true if a viewport should always force the width of this
* Scrollable to match the width of the viewport.
*
* @return true if a viewport should force the Scrollables width to
* match its own.
*/
public boolean getScrollableTracksViewportWidth() {
// PENDING(prinz) need to change this so the entire Scrollable
// interface comes from the installed EditorKit if it defines
// Scrollable, because many content types have a kind of scrolling
// policy (eg html has preformatted areas that define minimum width,
// and rtf has a defined page size).
return true;
}
/////////////////
// Accessibility support
////////////////
/**
* Get the AccessibleContext associated with this JEditorPane. A new
* context is created if necessary.
*
* @return the AccessibleContext of this JEditorPane
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJEditorPane();
}
return accessibleContext;
}
/**
* The class used to obtain the accessible role for this object.
* <p>
* Warning: serialized objects of this class will not be compatible with
* future swing releases. The current serialization support is appropriate
* for short term storage or RMI between Swing1.0 applications. It will
* not be possible to load serialized Swing1.0 objects with future releases
* of Swing. The JDK1.2 release of Swing will be the compatibility
* baseline for the serialized form of Swing objects.
*/
protected class AccessibleJEditorPane extends AccessibleJTextComponent {
/**
* Gets the accessibleDescription property of this object. If this
* property isn't set, return the content type of this JEditorPane
* instead (e.g. "plain/text", "html/text", etc.
*
* @return the localized description of the object; null if
* this object does not have a description
*
* @see #setAccessibleName
*/
public String getAccessibleDescription() {
if (accessibleDescription != null) {
return accessibleDescription;
} else {
return JEditorPane.this.getContentType();
}
}
/**
* Gets the state set of this object.
*
* @return an instance of AccessibleStateSet describing the states
* of the object
* @see AccessibleStateSet
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
states.add(AccessibleState.MULTI_LINE);
return states;
}
}
private static Hashtable getKitTypeRegistry() {
Hashtable kitTypeRegistry =
(Hashtable)SwingUtilities.appContextGet(kitTypeRegistryKey);
if (kitTypeRegistry == null) {
kitTypeRegistry = new Hashtable();
SwingUtilities.appContextPut(kitTypeRegistryKey, kitTypeRegistry);
}
return kitTypeRegistry;
}
// --- variables ---------------------------------------
/**
* Current content binding of the editor.
*/
private EditorKit kit;
/**
* Table of registered type handlers for this editor.
*/
private Hashtable typeHandlers;
/*
* Private AppContext keys for this class's static variables.
*/
private static final Object kitRegistryKey =
new StringBuffer("JEditorPane.kitRegistry");
private static final Object kitTypeRegistryKey =
new StringBuffer("JEditorPane.kitTypeRegistry");
static {
// set the default bindings
registerEditorKitForContentType("text/plain", "com.sun.java.swing.JEditorPane$PlainEditorKit");
registerEditorKitForContentType("text/html", "com.sun.java.swing.text.html.HTMLEditorKit");
registerEditorKitForContentType("text/rtf", "com.sun.java.swing.text.rtf.RTFEditorKit");
registerEditorKitForContentType("application/rtf", "com.sun.java.swing.text.rtf.RTFEditorKit");
}
static class PlainEditorKit extends DefaultEditorKit implements ViewFactory {
/**
* Fetches a factory that is suitable for producing
* views of any models that are produced by this
* kit. The default is to have the UI produce the
* factory, so this method has no implementation.
*
* @return the view factory
*/
public ViewFactory getViewFactory() {
return this;
}
/**
* Creates a view from the given structural element of a
* document.
*
* @param elem the piece of the document to build a view of
* @return the view
* @see View
*/
public View create(Element elem) {
return new WrappedPlainView(elem);
}
}
}